package com.passer.simpletransfer.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.passer.simpletransfer.config.STWebSocketConfigurer;
import com.passer.simpletransfer.model.ChatUser;
import com.passer.simpletransfer.model.UserMessage;
import com.passer.simpletransfer.websocket.contant.WebSocketMessageType;
import com.passer.simpletransfer.websocket.vo.WebSocketMessageVo;
import com.passer.toolbox.common.core.util.DateUtils;
import com.passer.toolbox.common.core.util.UUIDUtils;
import com.passer.toolbox.common.core.util.UserNameUtils;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Getter
@Component
@ServerEndpoint(value = "/websocket/chat/{token}", configurator = STWebSocketConfigurer.class)
public class ChatWebSocketService extends BaseWebSocketServer {

    protected static final HashMap<String, List<String>> errorMessageMap = new HashMap<>();

    private String userName;

    @OnOpen
    @Override
    public void onOpen(Session session, @PathParam("token") String token) {
        String id;
        String chineseUserName;
        if ("-".equals(token)) {
            id = UUIDUtils.fastUUID();
            chineseUserName = UserNameUtils.createChineseUserName();
        } else {
            String[] strings = token.split("-");
            id = strings[0];
            chineseUserName = strings[1];
        }
        super.onOpen(session, id);
        this.userName = chineseUserName;
        webSocketMap.put(id, this);
        WebSocketMessageVo<ChatUser> messageVo = new WebSocketMessageVo<>();
        messageVo.setType(WebSocketMessageType.USER_INFO);
        ChatUser chatUser = new ChatUser();
        chatUser.setChatUserId(id);
        chatUser.setChatUserName(chineseUserName);
        chatUser.setContent(0);
        messageVo.setData(chatUser);
        sendMessage(id, messageVo);
        resendErrorMessage();
    }

    @Override
    @OnClose
    public void onClose() {
        super.onClose();
    }

    @Override
    @OnMessage
    public void onMessage(String message, Session session) {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode;
        try {
            jsonNode = objectMapper.readTree(message);
        } catch (JsonProcessingException e) {
            log.error("【{}】消息接收失败：消息内容格式化失败", this.getClass().getSimpleName(), e);
            return;
        }
        String type = jsonNode.get("type").textValue();
        WebSocketMessageType messageType;
        try {
            messageType = WebSocketMessageType.valueOf(type);
        } catch (IllegalArgumentException e) {
            log.error("【{}】消息类型{}不受支持", this.getClass().getSimpleName(), type);
            return;
        }
        switch (messageType) {
            case USER_MESSAGE:
                UserMessage userMessage;
                try {
                    userMessage = objectMapper.treeToValue(jsonNode.get("data"), UserMessage.class);
                } catch (JsonProcessingException e) {
                    log.error("【{}】消息接收失败：消息内容格式化失败", this.getClass().getSimpleName(), e);
                    return;
                }
                userMessage.setFrom(super.userToken);
                userMessage.setSendTime(DateUtils.getTime());
                userMessage.setStatus("succeed");
                WebSocketMessageVo<UserMessage> userMessageVo = new WebSocketMessageVo<>();
                userMessageVo.setType(WebSocketMessageType.USER_MESSAGE);
                userMessageVo.setData(userMessage);
                sendAllMessage(userMessageVo, (result, messageString) -> {
                    if (result) {
                        return;
                    }
                    List<String> errorMessageList;
                    if (errorMessageMap.containsKey(this.userToken)) {
                        errorMessageList = errorMessageMap.get(this.userToken);
                    } else {
                        errorMessageList = new ArrayList<>();
                    }
                    errorMessageList.add(messageString);
                    errorMessageMap.put(this.userToken, errorMessageList);
                });
                break;
            case HEARTBEAT:
                WebSocketMessageVo<Long> messageVo = new WebSocketMessageVo<>();
                messageVo.setType(WebSocketMessageType.HEARTBEAT);
                messageVo.setData(System.currentTimeMillis());
                sendMessage(this.userToken, messageVo);
                break;
        }

    }

    private void sendToOtherUser(String from, WebSocketMessageVo<UserMessage> webSocketMessageVo) {
        for (ChatUser chatUser : getChatUsers(from, false)) {
            sendMessage(chatUser.getChatUserId(), webSocketMessageVo);
        }
    }

    private void resendErrorMessage() {
        if (!errorMessageMap.containsKey(this.userToken)) {
            return;
        }
        List<String> list = errorMessageMap.get(this.userToken);
        List<String> errorMessageList = new ArrayList<>();
        for (String message : list) {
            boolean result = sendMessage(message, this);
            if (!result) {
                errorMessageList.add(message);
            }
        }
        errorMessageMap.put(this.userToken, errorMessageList);
    }

    public static List<ChatUser> getChatUsers(String selfId, boolean needAll) {
        List<ChatUser> chatUsers = new ArrayList<>();
        webSocketMap.forEach((key, value) -> {
            if (!key.equals(selfId)) {
                ChatUser chatUser = new ChatUser();
                chatUser.setChatUserId(key);
                if (value instanceof ChatWebSocketService) {
                    chatUser.setChatUserName(((ChatWebSocketService) value).getUserName());
                }
                chatUsers.add(chatUser);
            }
        });
        if (needAll) {
            ChatUser chatUserVo = new ChatUser("all", "大群", 0);
            chatUsers.add(chatUserVo);
        }
        return chatUsers;
    }

    public static Map<String, ChatUser> getChatUserMap(String selfId, boolean needAll) {
        Map<String, ChatUser> chatUserMap = new HashMap<>();
        webSocketMap.forEach((key, value) -> {
            if (!key.equals(selfId)) {
                ChatUser chatUser = new ChatUser();
                chatUser.setChatUserId(key);
                if (value instanceof ChatWebSocketService) {
                    chatUser.setChatUserName(((ChatWebSocketService) value).getUserName());
                }
                chatUserMap.put(key, chatUser);
            }
        });
        if (needAll) {
            ChatUser chatUser = new ChatUser("all", "大群", 0);
            chatUserMap.put(chatUser.getChatUserId(), chatUser);
        }
        return chatUserMap;
    }

}
